11. 完成情感分析 RNN
参考 Solution 代码
要详细查看 solution 代码,请转到 solution workspace 或在线查看。
完成 RNN 类
一定自己去尝试定义该模型并使代码能正常运行!要勤学多练哟!下面说说我是如何定义该模型的。
该模型包括一个嵌入层、一个递归层以及一个最终线性层级,并应用 S 型函数;我在
__init__
函数中根据传入的参数定义了所有这些层级。
def __init__(self, vocab_size, output_size, embedding_dim, hidden_dim, n_layers, drop_prob=0.5):
"""
Initialize the model by setting up the layers.
"""
super(SentimentRNN, self).__init__()
self.output_size = output_size
self.n_layers = n_layers
self.hidden_dim = hidden_dim
# embedding and LSTM layers
self.embedding = nn.Embedding(vocab_size, embedding_dim)
self.lstm = nn.LSTM(embedding_dim, hidden_dim, n_layers,
dropout=drop_prob, batch_first=True)
# dropout layer
self.dropout = nn.Dropout(0.3)
# linear and sigmoid layers
self.fc = nn.Linear(hidden_dim, output_size)
self.sig = nn.Sigmoid()
__init__
函数
首先是一个嵌入层,参数包括词汇表的大小(即整数标记的数量),并生成一个大小为 embedding_dim
的嵌入向量。在模型训练过程中,此函数将创建一个嵌入查询表,行数等于整数标记的数量,列数等于嵌入维度。
然后是一个 LSTM 层级,参数为大小是 embedding_dim
的输入。它将嵌入向量当做输入,并生成一个输出和某个隐藏大小的隐藏状态。我还指定了几个层级和丢弃值,最后将 batch_first
设为 True,因为我们要使用数据加载器批处理数据。
然后将 LSTM 输出传入丢弃层,接着是全连接线性层级,该线性层级将生成 output_size
个输出。最后定义一个 S 型层级,将输出转换为 0-1 之间的值。
前馈行为
接着定义 forward
函数,它的参数包括输入 x
和hidden
状态,我将按顺序将输入传入这些层级。
def forward(self, x, hidden):
"""
Perform a forward pass of our model on some input and hidden state.
"""
batch_size = x.size(0)
# embeddings and lstm_out
embeds = self.embedding(x)
lstm_out, hidden = self.lstm(embeds, hidden)
# stack up lstm outputs
lstm_out = lstm_out.contiguous().view(-1, self.hidden_dim)
# dropout and fully-connected layer
out = self.dropout(lstm_out)
out = self.fc(out)
# sigmoid function
sig_out = self.sig(out)
# reshape to be batch_size first
sig_out = sig_out.view(batch_size, -1)
sig_out = sig_out[:, -1] # get last batch of labels
# return last sigmoid output and hidden state
return sig_out, hidden
forward
函数
首先获取输入 x 的 batch_size
,用于变形数据。然后将 x 传入嵌入层,生成嵌入向量
将这些嵌入和隐藏状态传入 LSTM 层级,返回一个 lstm_output
和新的 hidden
状态。然后将 LSTM 的输出堆叠起来并传入最后的线性层级。
继续将变形后的 lstm_output
传入丢弃层和线性层级,返回一定数量的输出,并将这些输出传入 S 型激活函数。
对于一批输入数据,我希望仅返回最后一个 S 型激活函数输出,所以将这些输出设为 batch_size
first。然后通过调用 sig_out[:, -1]
获取最后一个批次,这样就会获得最后一批标签。
最后,返回该输出和 LSTM 层级生成的隐藏状态。
init_hidden
这样就完成了 forward 函数,还有一个:init_hidden
,它和之前看到的一样。LSTM 的隐藏状态和单元状态是值元组,每个值的大小为(n_layers * batch_size* hidden_dim)。将所有这些隐藏权重初始化为 0,并移到 GPU 上(如果有 GPU 的话)。
def init_hidden(self, batch_size):
''' Initializes hidden state '''
# Create two new tensors with sizes n_layers x batch_size x hidden_dim,
# initialized to zero, for hidden state and cell state of LSTM
weight = next(self.parameters()).data
if (train_on_gpu):
hidden = (weight.new(self.n_layers, batch_size, self.hidden_dim).zero_().cuda(),
weight.new(self.n_layers, batch_size, self.hidden_dim).zero_().cuda())
else:
hidden = (weight.new(self.n_layers, batch_size, self.hidden_dim).zero_(),
weight.new(self.n_layers, batch_size, self.hidden_dim).zero_())
return hidden
接着就可以实例化并训练此模型了,你可以通过多次尝试并找到合适的超参数,还可以在下个页面查看 solution 代码。